﻿#include "DrawUtils.h"

#include <Windows.h>

#include "../Utils/Logger.h"
#include "../Memory/GameData.h"
#include "../HeliumClient/Modules/ModulesManager.h"

DrawUtils::mce__VertexFormat__disableHalfFloats_t DrawUtils::mce__VertexFormat__disableHalfFloats{};
DrawUtils::Tessellator__initializeFormat_t DrawUtils::Tessellator__initializeFormat{};

C_MinecraftUIRenderContext* DrawUtils::renderCtx{};
uintptr_t DrawUtils::screenContext2d{};
uintptr_t DrawUtils::game3dContext{};
Tessellator* DrawUtils::tesselator{};
float* DrawUtils::colorHolder{};
glmatrixf DrawUtils::refdef{};
vec2_t DrawUtils::fov{};
vec2_t DrawUtils::screenSize{};
vec3_t DrawUtils::origin{};
float DrawUtils::lerpT{};
MaterialPtr* DrawUtils::uiMaterial{};
MaterialPtr* DrawUtils::entityFlatStaticMaterial{};

MC_Color DrawUtils::last_color{};

DrawUtils::tess_vertex_t DrawUtils::tess_vertex{};
DrawUtils::meshHelper_renderImm_t DrawUtils::meshHelper_renderImm{};

void DrawUtils::init() {
	const auto base = Utils::Utils::getBase();
	tess_vertex = reinterpret_cast<tess_vertex_t>(base + 13437584);
	meshHelper_renderImm = reinterpret_cast<meshHelper_renderImm_t>(base + 20219712);

	const uintptr_t sigOffset = base + 9357599;
	int offset = *reinterpret_cast<int*>(sigOffset + 3);
	uiMaterial = reinterpret_cast<MaterialPtr*>(sigOffset + offset + 7);
}

void DrawUtils::setCtx(C_MinecraftUIRenderContext* ctx, const C_GuiData* guiData) {
	renderCtx = ctx;
	screenContext2d = reinterpret_cast<__int64*>(renderCtx)[2];
	tesselator = *reinterpret_cast<Tessellator**>(screenContext2d + 0xB0);
	colorHolder = *reinterpret_cast<float**>(screenContext2d + 0x30);

	const auto clientInstance = GameData::getClientInstance();
	const glmatrixf* badrefdef = clientInstance->getRefDef();

	refdef = badrefdef->correct();
	fov = clientInstance->getFov();
	screenSize.x = guiData->widthGame;
	screenSize.y = guiData->heightGame;

	if (clientInstance->levelRenderer != nullptr) [[likely]] 
		origin = clientInstance->levelRenderer->getOrigin();

	__try {
		if (entityFlatStaticMaterial == nullptr && GameData::isInGame()) [[unlikely]]
			entityFlatStaticMaterial = reinterpret_cast<MaterialPtr*>(clientInstance->itemInHandRenderer->entityLineMaterial.materialPtr);
	} __except (EXCEPTION_EXECUTE_HANDLER) {
	}
	
}

void DrawUtils::setGameRenderContext(uintptr_t ctx) {
	game3dContext = ctx;
	const auto clientInstance = GameData::getClientInstance();

	if (clientInstance->levelRenderer != nullptr) [[likely]] 
		origin = clientInstance->levelRenderer->getOrigin();

}

void DrawUtils::flush() {
	renderCtx->flushText(0.f);
}

void DrawUtils::setColor(float r, float g, float b, float a) {
	colorHolder[0] = r;
	colorHolder[1] = g;
	colorHolder[2] = b;
	colorHolder[3] = a;
	*reinterpret_cast<uint8_t*>(colorHolder + 4) = 1ui8;
	last_color.r = r;
	last_color.g = g;
	last_color.b = b;
	last_color.a = a;
}

inline void DrawUtils::tess__begin(Tessellator* tesselator, int vertexFormat, int numVerticesReserved) {
	using tess_begin_t = void(__fastcall*)(Tessellator*, int, int);
	static const tess_begin_t tess_begin = reinterpret_cast<tess_begin_t>(Utils::Utils::getBase() + 13436048);
	tess_begin(tesselator, vertexFormat, numVerticesReserved);
}

C_Font* DrawUtils::getFont(Fonts font) {
	const auto clientInstance = GameData::getClientInstance();

	switch (font) {
	case Fonts::SMOOTH:
		return clientInstance->minecraftGame->getTheGoodFontThankYou();
	case Fonts::UNICOD:
		return clientInstance->minecraftGame->getTheBetterFontYes();
	case Fonts::RUNE:
		return clientInstance->_getRuneFont();
	case Fonts::MC:
		return clientInstance->minecraftGame->mcFont;
	default:
		return clientInstance->_getFont();
	}
}

Tessellator* DrawUtils::get3dTessellator() {
	return *reinterpret_cast<Tessellator**>(game3dContext + 0xB0);
}

uintptr_t DrawUtils::getScreenContext() {
	return game3dContext == 0 ? screenContext2d : game3dContext;
}

MatrixStack* DrawUtils::getMatrixStack() {
	return reinterpret_cast<MatrixStack*>(*reinterpret_cast<uintptr_t*>(DrawUtils::getScreenContext() + 0x18i64) + 0x30i64);
}

float DrawUtils::getTextWidth(std::u8string_view textStr, float textSize, Fonts font) {
	TextHolder_view text(textStr);

	C_Font* fontPtr = getFont(font);

	return renderCtx->getLineLength(fontPtr, &text, textSize, false);
}

float DrawUtils::getFontHeight(float textSize, Fonts font) {
	C_Font* fontPtr = getFont(font);

	return fontPtr->getLineHeight() * textSize;
}

void DrawUtils::drawLine(vec2_t start, vec2_t end, float lineWidth) noexcept {
	float modX = end.y - start.y;
	float modY = start.x - end.x;

	float len = sqrtf(modX * modX + modY * modY);

	modX /= len;
	modY /= len;
	modX *= lineWidth;
	modY *= lineWidth;

	DrawUtils::tess__begin(tesselator, 3, 6);

	tess_vertex(tesselator, start.x + modX, start.y + modY, 0);
	tess_vertex(tesselator, start.x - modX, start.y - modY, 0);
	tess_vertex(tesselator, end.x - modX, end.y - modY, 0);

	tess_vertex(tesselator, start.x + modX, start.y + modY, 0);
	tess_vertex(tesselator, end.x + modX, end.y + modY, 0);
	tess_vertex(tesselator, end.x - modX, end.y - modY, 0);

	meshHelper_renderImm(screenContext2d, tesselator, uiMaterial);
}